window.onload = function () {
  const canvas = document.getElementById("canvas");
  const context = canvas.getContext("2d");
  const eraseAllButton = document.getElementById("eraseAllButton"),
    strokeStyleSelect = document.getElementById("strokeStyleSelect"),
    fillStyleSelect = document.getElementById("fillStyleSelect"),
    sidesSelect = document.getElementById("sidesSelect"),
    fillCheckbox = document.getElementById("fillCheckbox"),
    editCheckbox = document.getElementById("editCheckbox");

  let drawingSurfaceImageData,
    mousedown = {},
    rubberbandRect = {},
    dragging = false,
    draggingOffsetX,
    draggingOffsetY,
    sides = 8,
    startAngle = 0,
    guidewires = true,
    editing = false,
    polygons = [];

  var Point = function (x, y) {
    this.x = x;
    this.y = y;
  };
  // polygon 对象
  var Polygon = function (
    centerX,
    centerY,
    radius,
    sides,
    startAngle,
    strokeStyle,
    fillStyle,
    filled
  ) {
    this.centerX = centerX;
    this.centerY = centerY;
    this.radius = radius;
    this.sides = sides;
    this.startAngle = startAngle;
    this.strokeStyle = strokeStyle;
    this.fillStyle = fillStyle;
    this.filled = filled;
  };

  Polygon.prototype = {
    getPoints: function () {
      let points = [],
        angle = this.startAngle || 0;
      for (var i = 0; i < this.sides; i++) {
        points.push(
          new Point(
            this.centerX + this.radius * Math.cos(angle),
            this.centerY + this.radius * Math.sin(angle)
          )
        );
        angle += (Math.PI * 2) / this.sides;
      }
      return points;
    },
    createPath: function () {
      const points = this.getPoints();
      context.beginPath();
      context.moveTo(points[0].x, points[0].y);
      for (var i = 1; i < points.length; i++) {
        context.lineTo(points[i].x, points[i].y);
      }
      context.closePath();
    },
    stroke: function () {
      context.save();
      this.createPath();
      context.strokeStyle = this.strokeStyle;
      context.stroke();
      context.restore();
    },
    fill: function () {
      context.save();
      this.createPath();
      context.fillStyle = this.fillStyle;
      context.fill();
      context.restore();
    },
    move: function (x, y) {
      this.x = x;
      this.y = y;
    },
  };
  function windowToCanvas(x, y) {
    const bbox = canvas.getBoundingClientRect();
    return {
      x: x - bbox.left,
      y: y - bbox.top,
    };
  }

  // 画辅助线
  function drawVerticalLine(x) {
    context.beginPath();
    context.moveTo(x, 0);
    context.lineTo(x, canvas.height);
    context.stroke();
  }
  function drawHorizontalLine(y) {
    context.beginPath();
    context.moveTo(0, y);
    context.lineTo(canvas.width, y);
    context.stroke();
  }
  function drawGuidWires(x, y) {
    context.save();
    context.strokeStyle = "rgba(0,0,230,0.4)";
    context.lineWidth = 0.5;
    drawVerticalLine(x);
    drawHorizontalLine(y);
    context.restore();
  }
  function saveDrawingSurface() {
    drawingSurfaceImageData = context.getImageData(
      0,
      0,
      canvas.width,
      canvas.height
    );
  }

  function restoreDrawingSurface() {
    context.putImageData(drawingSurfaceImageData,0,0);
  }
  function startDragging(loc) {
    saveDrawingSurface();
    mousedown.x = loc.x;
    mousedown.y = loc.y;
    dragging = true;
  }

  function updateRubberbandRec(loc) {
    rubberbandRect.width = Math.abs(mousedown.x - loc.x);
    rubberbandRect.height = Math.abs(mousedown.y - loc.y);
    mousedown.x - loc.x > 0
      ? (rubberbandRect.left = loc.x)
      : (rubberbandRect.left = mousedown.x);

    mousedown.y - loc.y > 0
      ? (rubberbandRect.top = loc.y)
      : (rubberbandRect.top = mousedown.y);
  }
  function drawPolygon(polygon){
    // polygon.createPath();
    polygon.stroke();
    if(fillCheckbox.checked){
      polygon.fill();
    }
    
  }
  function drawRubberbandShape(loc, sides, startAngle) {
    var polygon = new Polygon(
      mousedown.x,
      mousedown.y,
      rubberbandRect.width,
      parseInt(sidesSelect.value),
      (Math.PI / 180) * parseInt(startAngle),
      context.strokeStyle,
      context.fillStyle,
      true
    );
    drawPolygon(polygon);
    if (!dragging) {
      polygons.push(polygon);
    }
  }
  function updateRubberband(loc, sides, startAngle) {
    updateRubberbandRec(loc);
    drawRubberbandShape(loc, sides, startAngle);
  }

  function drawPolygons(){
    polygons.forEach(polygon => {
      drawPolygon(polygon);
    })
  }

  function drawGrid(color,stepX,stepY){
    context.save();
    context.strokeStyle = 'gray';
    context.lineWidth = 0.5;
    
    for(var i = stepX;i<canvas.width;i = i+ stepX){
      context.beginPath();
      context.moveTo(i,0);
      context.lineTo(i,canvas.height);
      context.stroke();
    }
    for(var i = stepY;i<canvas.height;i = i+ stepY){
      context.beginPath();
      context.moveTo(0,i);
      context.lineTo(canvas.width,i);
      context.stroke();
    }
    context.restore();

  }
  canvas.onmousedown = function (e) {
    const loc = windowToCanvas(e.clientX, e.clientY);
    e.preventDefault();
    if (editing) {
      // 拖动
      polygons.forEach(function(polygon){
        polygon.createPath();
        // CanvasRenderingContext2D.isPointInPath()是 Canvas 2D API 用于判断在当前路径中是否包含检测点的方法。
        if(context.isPointInPath(loc.x,loc.y)){
          startDragging(loc);
          dragging = polygon;
          draggingOffsetX = loc.x - polygon.centerX;
          draggingOffsetY = loc.y - polygon.centerY;
          return;
        }
      })
    } else {
      // 绘制
      startDragging(loc);
      dragging = true;
    }
  };
  canvas.onmousemove = function (e) {
    const loc = windowToCanvas(e.clientX, e.clientY);
    e.preventDefault();
    if (editing && dragging) {
      dragging.centerX = loc.x - draggingOffsetX;
      dragging.centerY = loc.y - draggingOffsetY;
      context.clearRect(0,0,canvas.width,canvas.height)
      drawGrid('lightgray',10,10);
      drawPolygons();
    } else {
      if (dragging) {
        restoreDrawingSurface();
        updateRubberband(loc, sides, startAngle);
        if(guidewires){
          drawGuidWires(mousedown.x,mousedown.y)
        }
      }
    }
  };

  canvas.onmouseup = function(e){
    var loc = windowToCanvas(e.clientX,e.clientY)
    dragging = false;
    if(editing){
      
    }else{
      restoreDrawingSurface();
      updateRubberband(loc);
    }

  }

  context.strokeStyle = strokeStyleSelect.value;
  context.fillStyle = fillStyleSelect.value;

  drawGrid('lightgray',10,10)

  eraseAllButton.onclick = function(){
    context.clearRect(0,0,canvas.width,canvas.height)
    drawGrid('lightgray',10,10)
  }
  
  function startEditing(){
    editing = true;
    canvas.style.cursor = 'crosshair'
  }
  function stopEditing(){
    editing = false;
    canvas.style.cursor = 'pointer'
  
  }
  editCheckbox.onchange = function(e){
    if(editCheckbox.checked){
      startEditing();
    }else {
      stopEditing();
    }
  }

  strokeStyleSelect.onchange = function(e){
    context.strokeStyle = strokeStyleSelect.value;
  }
  fillStyleSelect.onchange = function(e){
    context.fillStyle = fillStyleSelect.value;
  }
};

